﻿//last modified：2020/1/20，ben，修改排程日期规则，8小时为1天，宽放3天，委外5天，最长90天；
using AchieveBLL;
using AchieveDAL;
using AchieveCommon;
using AchieveEntity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Data;
using System.Text;
using System.Data.SqlClient;
using AchieveManageWeb.Models.ActionFilters;

namespace AchieveManageWeb.Controllers
{

     [AchieveManageWeb.App_Start.JudgmentLogin]
    public class ScheduleController : Controller
    {
        //
        // GET: /Schedule/

        public ActionResult Index()
        {
            return View();
        }

        /// <summary>
        /// 获取工序计划表，输入FBillNo，ICMO.FBillNo==shworkbill.FICMONO，暂不支持分页，该功能暂不交付，保留下一步使用
        /// </summary>
        /// <returns></returns>
        public ActionResult doSchedule()
        {
            string t = ConfigHelper.ReadConfig("MOclTime");
            Int32 MOclTime = string.IsNullOrWhiteSpace(t) ? 3 : Convert.ToInt32(t); //默认完工提前日为3天

            //首先获取前台传递过来的参数
            string FBillNo;
            if (string.IsNullOrWhiteSpace(Request["FBillNo"]))
            {
                return Content("{\"msg\":\"修改失败,未获取到订单号\",\"success\":false}");                
            }
            else
            {
                FBillNo = Request["FBillNo"];
            }

            SqlParameter[] paras = new SqlParameter[]{                        
                new SqlParameter("@FBillNo", SqlDbType.VarChar) { Value = FBillNo} 
            };

            string sql = "select fwbinterid,fentryid,fplanstartdate,fplanenddate,ftotalworktime,FEntrySelfz0374,FEntrySelfz0375,FPlanCommitDate,FPlanFinishDate  from shworkbillentry a left join ICMO b on a.FEntrySelfz0373=b.FBillNo where FEntrySelfz0373=@FBillNo order by fentryid desc";
            DataTable dt = SqlHelper.GetDataTable(SqlHelper.connStrK3, CommandType.Text, sql, paras);
            DateTime planED = Convert.ToDateTime(dt.Rows[0]["FPlanFinishDate"]);
            DateTime fpday = planED.AddDays(-MOclTime);//
            List<string> sqllist = new List<string>();

            //进入倒排工期计算
            try
            {
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    int fwbinterid = (int)dt.Rows[i]["fwbinterid"];
                    dt.Rows[i]["FEntrySelfz0375"] = fpday;
                    sqllist.Add("update shworkbillentry set FEntrySelfz0375='" + fpday.ToString() + "' where fwbinterid=" + fwbinterid);
                    double ftotalworktime = Convert.ToDouble(dt.Rows[i]["ftotalworktime"]);//数据库字段为decimal类型
                    int days = (int)Math.Ceiling(ftotalworktime / 8);//转换为天；
                    fpday = fpday.AddDays(-days);
                    dt.Rows[i]["FEntrySelfz0374"] = fpday;
                    sqllist.Add("update shworkbillentry set FEntrySelfz0374='" + fpday.ToString() + "' where fwbinterid=" + fwbinterid);
                    fpday = fpday.AddDays(-1);//保证前置工序提前1天完成
                }
                //写入数据库；
                int count = SqlHelper.ExecuteNonQuery(SqlHelper.connStrK3, sqllist);

                string result = "{\"msg\":\"排程计算完成,成功写入数据" + count + "条!\",\"success\":true}";

                return Content(result);
            }
            catch (Exception ex)
            {
                return Content("{\"msg\":\"修改失败," + ex.Message + "\",\"success\":false}");
            }

        }

         /// <summary>
         /// 未使用！
         /// 根据生产任务单单号和完工日期，倒排计算隶属工序单的时间，不考虑提前完工时间
         /// </summary>
         /// <param name="FBillNo">任务单单号，主单和子单同样对待</param>
         /// <param name="finishDate">任务单完工日期</param>
         /// <returns></returns>
        public int scheduleByFBillNo(string FBillNo, DateTime finishDate)
        {           
            SqlParameter[] paras = new SqlParameter[]{ 
                new SqlParameter("@FBillNo", SqlDbType.VarChar) { Value = FBillNo} 
            };
            string sql = "select fwbinterid,fentryid,ftotalworktime,FEntrySelfz0374,FEntrySelfz0375  from shworkbillentry where FEntrySelfz0373=@FBillNo order by fentryid desc";
            DataTable dt = SqlHelper.GetDataTable(SqlHelper.connStrK3, CommandType.Text, sql, paras);
            DateTime fpday = finishDate; 
            List<string> sqllist = new List<string>();
            //进入倒排工期计算
            try
            {
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    int fwbinterid = (int)dt.Rows[i]["fwbinterid"];
                    dt.Rows[i]["FEntrySelfz0375"] = fpday;
                    sqllist.Add("update shworkbillentry  WITH(HOLDLOCK)  set FEntrySelfz0375='" + fpday.ToString() + "' where fwbinterid=" + fwbinterid);
                    double ftotalworktime = Convert.ToDouble(dt.Rows[i]["ftotalworktime"]);//数据库字段为decimal类型
                    int days = (int)Math.Ceiling(ftotalworktime / 8);//转换为天；
                    fpday = fpday.AddDays(-days);
                    dt.Rows[i]["FEntrySelfz0374"] = fpday;
                    sqllist.Add("update shworkbillentry  WITH(HOLDLOCK)  set FEntrySelfz0374='" + fpday.ToString() + "' where fwbinterid=" + fwbinterid);
                    fpday = fpday.AddDays(-1);//保证前置工序提前1天完成
                }
                //写入数据库；
                int count = SqlHelper.ExecuteNonQuery(SqlHelper.connStrK3, sqllist);
                return count;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        
        }
         /// <summary>
         /// 排程基本函数，输入生产任务单，完工日期，对该任务单所属的所有工单进行排程，返回最迟备货日期；
         /// 规则：工时每8小时算1天，最小单位1天，工时为0的计3天，因为0一般为委外！
         /// </summary>
         /// <param name="FBillNo">任务单号</param>
         /// <param name="finishDate">最迟完工日期</param>
        /// <returns>最迟备货日期</returns>
        public DateTime scheduleByFBillNoDatetime(string FBillNo, DateTime finishDate)
        {
            SqlParameter[] paras = new SqlParameter[]{ 
                new SqlParameter("@FBillNo", SqlDbType.VarChar) { Value = FBillNo} 
            };
            string sql = "select fwbinterid,fentryid,ftotalworktime,FEntrySelfz0374,FEntrySelfz0375  from shworkbillentry where FEntrySelfz0373=@FBillNo order by fentryid desc";
            DataTable dt = SqlHelper.GetDataTable(SqlHelper.connStrK3, CommandType.Text, sql, paras);
            DateTime fpday = finishDate;
            DateTime fpdayTemp;
            List<string> sqllist = new List<string>();
            //进入倒排工期计算
            try
            {
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    int fwbinterid = (int)dt.Rows[i]["fwbinterid"];
                    //dt.Rows[i]["FEntrySelfz0375"] = fpday;
                   
                    double ftotalworktime = Convert.ToDouble(dt.Rows[i]["ftotalworktime"]);//数据库字段为decimal类型                    
                    int days = 3+(int)Math.Ceiling(ftotalworktime / 8);//转换为天；//最少一天 ，所有工序放宽3天，即至少4天；                   
                    if (days==0)
                    {
                        days = 5;//工时为0的日期定为5天，考虑一般为委外工单；
                    }
                    else if (days>90)//最长排程时长为90天；
                    {
                        days = 90;
                    }
                     
                    fpdayTemp = fpday.AddDays(1-days);//当天已有一天！
                    sqllist.Add("update shworkbillentry  WITH(HOLDLOCK)  set FEntrySelfz0374='" + fpdayTemp.ToString() + "', FEntrySelfz0375='" + fpday.ToString() + "' where fwbinterid=" + fwbinterid);
                    fpday = fpdayTemp.AddDays(-1);//保证前置工序提前1天完成                    
                }
                //写入数据库；
                int count = SqlHelper.ExecuteNonQuery(SqlHelper.connStrK3, sqllist);
               // System.Diagnostics.Debug.WriteLine("update:" + FBillNo+"，数据："+count);
                return fpday;//返回排程后得出的最迟备货日期
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

      
         /// <summary>
         /// 完整排程，分两步执行，第一步：取所有未完成未逾期的主生产计划单，按bom层级从主单完工日期倒排；
         /// 第二步：对经过第一步后含未排程工单的计划单，以该计划单的完工日期单独进行倒排；此时不考虑提前完工日期！
         /// 规则：1、逾期任务单，交货期改为当天日期后延15天；
         /// 2、未完成
        /// 3、主单提前完工日期，默认3天，ConfigHelper.ReadConfig("MOclTime");
         /// </summary>
         /// <returns></returns>
        public ActionResult doAllSchedule()
        {
            //try
            //{
                     string t = ConfigHelper.ReadConfig("MOclTime");
                                Int32 MOclTime = string.IsNullOrWhiteSpace(t) ? 3 : Convert.ToInt32(t); //默认完工提前日为3天
                                string returnMsg="排程处理任务单如下：";
                                //首先获取所有未完成未逾期的主生产计划单,规则：未关闭&&未完成&&计划完成时间>今天
                                StringBuilder sbsql = new StringBuilder();
                                //sbsql.Append("select  FItemID,FBillNo,FPlanCommitDate,FPlanFinishDate from ICMO where FStatus<3 and fmrpclosed=0 and  FPlanFinishDate>'"+DateTime.Now.ToString()+"' ");
                                //新规则，逾期工单按后延15天计算                
                                sbsql.Append("select  FItemID,FBillNo,FPlanCommitDate,FPlanFinishDate from ICMO where FStatus<3 and fmrpclosed=0 ");
                                  //抽取主作业计划单,规则不包含-、_两种连接符
                                 sbsql.Append( " and Fbillno not like '%v_%'  ESCAPE   'v'  and  Fbillno not like '%v-%' ESCAPE   'v'");
                                 DataTable dtMoMain = SqlHelper.GetDataTable(SqlHelper.connStrK3, sbsql.ToString());
                                 returnMsg += string.Format("主任务单共计{0}条；", dtMoMain.Rows.Count);
          
                                //对于每个主任务单，首先对其工单进行排程，然后获取其分层的未完工的子生产任务单；
                                 foreach (DataRow item in dtMoMain.Rows)
                                 {
                                     System.Diagnostics.Debug.WriteLine("开始处理单据:" + item["FBillNo"].ToString() );
                                     returnMsg += item["FBillNo"].ToString()+ ";"; 
                                     DateTime FPlanFinishDate = Convert.ToDateTime(item["FPlanFinishDate"]);
                                     if (FPlanFinishDate<DateTime.Now)//对逾期任务单，以当前日期延迟15天作为交货日期；
                                     {
                                         FPlanFinishDate = DateTime.Now.AddDays(15);
                                     }
                                     DateTime fday = FPlanFinishDate.AddDays(-MOclTime);//考虑提前完工日期；
                                     fday = scheduleByFBillNoDatetime(item["FBillNo"].ToString(), fday);//1、对主单的工序计划进行排程，返回进入主单工序的最迟日期
                                     //获取所有1级子单
                                     DataTable dtmochild = manufactureBLL.GetManufactureSubOrder(item["FBillNo"].ToString(), "FStatus<3", 1);
                 
                                     foreach (DataRow itemchild in dtmochild.Rows)
                                     {
                                         returnMsg += "处理子单:" + itemchild["FBillNo"].ToString() + ",完工日期:"+fday.ToString()+";"; 
                                         doScheduleLoop(itemchild, fday);
                                        
                                     }                
                                }
                          string   tempstr=  "根据主单进行排程处理完毕！进入排程第二阶段：找出含有未排程工单的生产计划单，不区分子单主单，直接排程；";
                                 System.Diagnostics.Debug.WriteLine(tempstr);
                                 returnMsg += tempstr;
                                 //排程第二阶段：找出含有未排程工单的生产计划单，不区分子单主单，直接排程；
                                 string sql2 = @"select  distinct b.fbillno,b.FPlanfinishdate from shworkbillentry a 
                                                left join icmo b on a.FEntrySelfz0373=b.FBillNo
                                                where a.fstatus <3 
                                                and a.fentryselfz0374 is null
                                                and b.fstatus<3
                                                and b.fmrpclosed=0 
                                                order by  b.fbillno";

                                 DataTable dtMoOther = SqlHelper.GetDataTable(SqlHelper.connStrK3, sql2.ToString());
                                tempstr=string.Format("问题任务单共计{0}条；", dtMoOther.Rows.Count);
                                returnMsg += tempstr;
                                 foreach (DataRow itemOther in dtMoOther.Rows)
                                 {
                                     tempstr = string.Format("开始处理计划单:{0},完工日期{1}；", itemOther["fbillno"].ToString(), itemOther["FPlanfinishdate"].ToString());
                                     returnMsg += tempstr; 
                                     scheduleByFBillNoDatetime(itemOther["fbillno"].ToString(), Convert.ToDateTime(itemOther["FPlanfinishdate"]));
                                 }

                                LoggerHelper.Info(returnMsg);
                                AchieveManageWeb.Models.ActionFilters.LoggerHelper.Notes(new AchieveManageWeb.Models.LogContent(ViewData, "自动排产", returnMsg)); //日志记录
                                string result = "{\"msg\":\"排程计算完成!"+returnMsg+"\",\"success\":true}";
                                return Content(result);
            //}
            //catch (Exception ex)
            //{
            //    return Content("{\"msg\":\"出现异常," + ex.Message + "\",\"success\":false}");
            //}
            
        }

        private void doScheduleLoop(DataRow mochild,DateTime fday) {
            DateTime fdaychild = scheduleByFBillNoDatetime(mochild["FBillNo"].ToString(), fday);//对1级子任务单进行排程，并返回最迟备货期
            //判断itemchild任务单是否有子单，如有，进行递归排程
            object x = mochild["hasChild"];
            if (Convert.ToBoolean(x))            
            {
                DataTable dtmochildc = manufactureBLL.GetManufactureSubOrder(mochild["FBillNo"].ToString(), "FStatus<3", 2);
                foreach (DataRow item in dtmochildc.Rows)
                {
                    doScheduleLoop(item, fdaychild);
                }
            }
            else
            {
                return;
            }
           // return DateTime.Now;        
        }
         /// <summary>
         /// 排程方式2，扫描所有生产任务单，不考虑子单主单，按当前任务单进行倒排；
         /// 用于在按主单倒排后，检查没有主单的任务单，根据其计划完工日期进行倒排；
         /// </summary>
        private void doScheduleSubICMO() { 
        
        }
    }
}
